#include "LinkList_Dynamic_lyvm.h"
#include "animationCenter.h"
#include "xVMRelationStruct.h"

#include "MappingEngine.h"
#include "xMappingTree.h"
#include "xNodeType_composite.h"
#include "xNodeType_WOP.h"
#include "xNodeType_VM.h"
#include "WOPInvokedObj.h"

//#include "include/Command_Agent.h"


//
// 關連到 StaticLayoutDialog 和 LinkedListSettingLayoutDialog 程式檔
//

extern HINSTANCE _hInst ;  // this instance is defined in DIVA_MAIN
extern HWND _hWnd ;        // this instance is defined in DIVA_Application
extern string valuableNames;
extern bool bRefIn;
extern bool bRefOut;
extern int level;
extern bool bCancel_dyn;
extern bool bCancel_sta;

// 記錄LinkedListSetting Layout Dialog中的屬性
extern std::vector<std::string> attrs;
extern std::string rightAttr;
extern std::string downAttr;

// event handler declaration
BOOL CALLBACK StaticLayoutDialog( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK LinkedListSettingLayoutDialog( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);



//
// LinkedList_Dynamic_lyvm 主體區
//


// constructor: 僅初始化必要參數
LinkList_Dynamic_Lyvm::LinkList_Dynamic_Lyvm()
{
	_flag = false;
	_name = "LinkList Dynamic Layout";
	_root = NULL;
	animationCenter::getInstance()->addAnimation(this);
}


// 取得下一個VM by name
DIVA_VM *LinkList_Dynamic_Lyvm::get_VM(DIVA_VM *vm, std::string attributeName)
{
	DIVA_VM *output = NULL;

	// 抓取vm的子VM，再用各個子VM反查父VM從哪一種attribute所指向
	// 藉此關連兩個VM的關係 :)
	vector<DIVA_VM*> kids = xVMRelationStruct::getInstance()->VMRS_nextVMsByRef(vm);
	vector<DIVA_VM*>::iterator it;
	for(it = kids.begin() ; it != kids.end() ; ++it){
		vector<DIVA_VM*> preVMs = xVMRelationStruct::getInstance()->VMRS_preVMsByRef((*it));
		vector<DIVA_VM*>::iterator itr;
		for(itr = preVMs.begin() ; itr != preVMs.end() ; itr++){
			if(vm->isSubComponent((*itr))){//如果找到preVMs是vm的SubComponent
				if((*itr)->get_vm_name() == attributeName) output = *it;	// 記錄對應於attributeName的子VM
			}
		}
	}

	// 即使DIVA_VM *ouput回傳NULL值  後序的呼叫方法仍可避免
	return output;
}


// template method: 初始化layout範圍及各項設定，在啟用layout時所呼叫
void LinkList_Dynamic_Lyvm::initial(DIVA_VM* startVM)
{
	// 開啟通用layout設定對話窗
	/*TODO:change to Qt dialog*/
	//DialogBox( _hInst, "SLAYDIA", _hWnd, (DLGPROC)StaticLayoutDialog);
	if(bCancel_sta == true) return;
	_area = new Ly_influence_area(startVM, bRefIn, bRefOut, valuableNames, level);	// 取得所有需要排列的VMs

	//linklist 需要root VM, list的第一個node為root, 未來展開需要知道root是那一個 , 排列也是一樣
	vector<DIVA_VM*> vms = _area->getAllVMs();
	this->searchRoot(vms);

	// 取得attributes
	WOP_Entry *entry = MappingEngine::getInstance()->get_entry_by_vm(_root);
	std::string structName = entry->getVarType();
	structName = structName.substr(0, structName.length()-1);	// 去除*  , ex: "bt*" -> "bt"
	// format:
	// [0]: var_1
	// [1]: var_1_type
	// [2]: var_2
	// [3]: var_2_type
	//  以此類推
	std::vector<std::string> attributes/* = Command_Agent::getInstance()->send_struct_and_parse(structName)*/;
	attrs = attributes;	// 將資料共享給LinkedListSettingLayoutDialog所使用  以初始化combobox資料
	
	// 顯示linked list layout Setting Dialog!!
	// 呼叫對應的event handler: LinkedListSettingLayoutDialog方法在上方↑↑↑
	/*TODO:change to Qt dialog*/
	//DialogBox( _hInst, "LinkedListSettingDialog", _hWnd, (DLGPROC)LinkedListSettingLayoutDialog);
	if(bCancel_sta == true) return;

	// 記錄向下、向右的attribute
	if(rightAttr != "") this->moveRightAttribute = rightAttr;
	if(downAttr  != "") this->moveDownAttribute  = downAttr;
}

// 未實作方法
void LinkList_Dynamic_Lyvm::showDialog()		{}
void LinkList_Dynamic_Lyvm::setupParameters()	{}
void LinkList_Dynamic_Lyvm::setupDialog()		{}


// method: 設定此layout的作用範圍
void LinkList_Dynamic_Lyvm::layout(std::vector<DIVA_VM*> vms, DIVA_VM *movedVM)
{
	//
	// 設定所有VM成為Linked list排列方式
	//

	this->searchRoot(vms);				// 1. 找root 考慮到如果root被移除或取代 , 要重新找一次root
	std::set<DIVA_VM*> vms_in_layout;	// 2. 使用向下、向下的屬性進行排列
	_record.clear();					// 2. 初始化, 清空各VM的位置

	// 先排右
	Ogre::Vector3 prePos = _root->getPosition();
	DIVA_VM *rightVM = this->get_VM(_root, this->moveRightAttribute);
	// 當子child不為null 而且子child尚未連結時 則進行關連
	while(rightVM != NULL && vms_in_layout.find(rightVM) == vms_in_layout.end())
	{
		// 將子child加入至已處理的layout set之中 避免cycle發生
		vms_in_layout.insert(rightVM);
		
		// 設定rightVM的位置
		// _record會被Basic_Dynamic_lyvm.setChanges()所使用
		_record[rightVM] = prePos + Ogre::Vector3(*rightVM->get_vm_sizex() + 50, 0, 0);

		// 取得下一個VM
		prePos = rightVM->getPosition();
		rightVM = this->get_VM(rightVM, this->moveRightAttribute);
	}

	// 再排下


	// 把剩下可能沒有給定位置的VM
	if(vms_in_layout.size() < _area->getAllVMs().size())
	{
		// do it!
	}
}


// Animable介面: 此方法會在每次frame更新時被呼叫
void LinkList_Dynamic_Lyvm::behavior(float timeSinceLastFrame)
{
	// 如果沒有啟用此layout 則跳出
	// 因為此方法會由AnimationCenter在每個frameStarted呼叫~
	if(!this->_flag) return;

	// 可能會用到
	if(_area != NULL){
		delete _area;
		_area = new Ly_influence_area(_root, bRefIn, bRefOut, valuableNames, level);
	}	

	// 做Linked List Layout
	this->layout(_area->getAllVMs(),_root);
	setChanges();	// 更新所有VM的排列位置
}







//
// 自用方法
//


void LinkList_Dynamic_Lyvm::determineChildsPosition(DIVA_VM* root,vector<pair<int,DIVA_VM*>> childs,int level_arg){
	Ogre::Vector3 obj_size = root->getActualSize();
	obj_size.z -= root->getActualSize().z;
	positionmap::iterator pmit;
	pmit = _record.find(root);
	Ogre::Vector3 root_pos;
	if(pmit != _record.end()){
		root_pos = _record[root];
	}
	else{
		root_pos = root->getPosition();
	}
	//insertPositionRecord(root,root_pos);
	Ogre::Real vertical_dis = obj_size.x;
	Ogre::Real horizontal_dis = (pow(2.0,level_arg-1)*obj_size.y)/2;
	vector<pair<int,DIVA_VM*>>::iterator it;
	for(it = childs.begin() ; it != childs.end() ; ++it){
		Ogre::Vector3 root_pos = _record[root]; 
		if((*it).first == 0){			
			Ogre::Vector3 left_final_dis = Ogre::Vector3(root_pos.x-horizontal_dis,root_pos.y-vertical_dis,0);
			//this->_record[(*it)] = left_final_dis;			
			//insertPositionRecord((*it).second,left_final_dis);
		}
		else{
			Ogre::Vector3 right_final_dis = Ogre::Vector3(root_pos.x+horizontal_dis,root_pos.y-vertical_dis,0);
			//this->_record[(*it)] = right_final_dis;
			//insertPositionRecord((*it).second,right_final_dis);
		}
	}
}


// method: 尋找root
void LinkList_Dynamic_Lyvm::searchRoot(vector<DIVA_VM*> vms){
	//往上找parent , 如果parent是與本身相同type的composite VM, 那本身就不是root , 
	//root的parent必為不同type的composite, how to determine type?
	//查wop?
	vector<DIVA_VM*>::iterator it;
	for(it = vms.begin() ; it != vms.end() ; ++it){
		vector<DIVA_VM*> parents = xVMRelationStruct::getInstance()->VMRS_preVMsByRef((*it));
		vector<DIVA_VM*>::iterator itr;
		for(itr = parents.begin() ; itr != parents.end() ; ++itr){
			DIVA_VM* vm = xVMRelationStruct::getInstance()->VMRS_toCompositeRootVM((*itr));
			if(vm == (*itr)){
				if(this->_root != NULL){
					(*it)->setPosition(this->_root->getPosition());
				}
				this->_root = (*it);
			}
		}
	}	
}

//
// end
//